//#########################################################################
//                              WackiEngie
//           Copyright (c) 2014 Marc Wacker. All rights reserved.
//#########################################################################

#pragma once

#include "WeUtilPrerequisites.h"
#include "WeVector2.h"

namespace WackiEngine
{

	template<class T>
	class Vector3 {
	public:
		T	x, y, z;

		Vector3(const T x_ = 0, const T y_ = 0, const T z_ = 0) { x = x_; y = y_; z = z_; }
		Vector3(const Vector2<T> &v) { x = v.x; y = v.y; z = 0; }
		Vector3(const Vector3 &v) { x = v.x; y = v.y; z = v.z; }

		void		set(T x_, T y_, T z_) { x = x_; y = y_; z = z_; }

		//compare operators
		bool		operator==	(const Vector3& b) const	{ return x == b.x && y == b.y && z == b.z; }
		bool		operator!=	(const Vector3& b) const	{ return x != b.x || y != b.y || z != b.z; }

		//operators with temp allocation
		Vector3	operator-	(void) const				{ return Vector3(-x, -y, -z); }
		Vector3	operator+	(const Vector3& v) const	{ return Vector3(x + v.x, y + v.y, z + v.z); }
		Vector3	operator-	(const Vector3& v) const	{ return Vector3(x - v.x, y - v.y, z - v.z); }
		T		operator*	(const Vector3& v) const	{ return x*v.x + y*v.y + z*v.z; };  // dot

		Vector3 operator*	(const T s) const			{ return Vector3(x*s, y*s, z*s); }
		Vector3 operator/	(const T s) const			{ return Vector3(x / s, y / s, z / s); }
		Vector3	operator&	(const Vector3& v) const	{ return Vector3(x*v.x, y*v.y, z*v.z); }

		friend Vector3 operator *  (T s, const Vector3& v)  { return Vector3(v.x*s, v.y*s, v.z*s); }

		//assign operators
		Vector3&	operator=	(const Vector2<T>& v)	{ x = v.x; y = v.y;	z = 0;		return *this; }
		Vector3&	operator=	(const Vector3& v)	{ x = v.x; y = v.y; z = v.z;		return *this; }
		Vector3&	operator+=	(const Vector3& v)	{ x += v.x; y += v.y; z += v.z;		return *this; }
		Vector3&	operator-=	(const Vector3& v)	{ x -= v.x; y -= v.y; z -= v.z;		return *this; }
		Vector3&	operator+=	(const T s)			{ x += s; y += s; z += s;			return *this; }
		Vector3&	operator-=	(const T s)			{ x -= s; y -= s; z -= s;			return *this; }
		Vector3&	operator*=	(const T s)			{ x *= s; y *= s; z *= s;			return *this; }
		Vector3&	operator/=	(const T s)			{ x /= s; y /= s; z /= s;			return *this; }
		Vector3&	operator&=	(const Vector3& v)	{ x *= v.x; y *= v.y; z *= v.z;		return *this; }

		T			dot(const Vector3&v)	const	{ return x * v.x + y * v.y + z * v.z; }
		Vector3<T>	cross(const Vector3 &v) const	{
			return Vector3<T>(	y * v.z - z * v.y,
								z * v.x - x * v.z,
								x * v.y - y * v.x);
		}
		T			lengthSq()						{ return x * x + y * y + z * z; }
		T			length()						{ return sqrt(lengthSq()); }
		void		normalize()						{ T l = length(); if(l>0) *this /= l; }
		Vector3		normalized()					{ T l = length(); if(l>0) return *this / l; }
	};


	typedef Vector3<float>		Vector3f;
	typedef Vector3<int32>		Vector3i;
}